﻿using Microsoft.Phone.Controls;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using WPNextTools.NBase;
using WPNextTools.NCommon;
using WPNextTools.NConstant;
using WPNextTools.NEventArgs;

namespace WPNextTools.NControls
{
    public class PhotoListBox : NControl, IItemsContainer
    {
        #region Fields
        internal ScrollViewer manipulationContainer;
        internal Canvas scrollableContent;
        internal Canvas itemsPanel;
        internal StackPanel mainContainer;
        internal ContentPresenter unionHeaderElement;
        internal Grid layoutRoot;
        #region ItemsSource
        private NListSource listSource;                 //将Items 转变成 DataSourceItems
        #endregion

        #region Recycle
        internal List<PhotoListBoxItem> realizedItems;  //显示的Containers
        private List<PhotoListBoxItem> recycleItems;    //容器池
        #endregion

        internal VirtualizationStrategy strategy;       //负责UI布局的策划者
        internal VirtualizationStrategyDefinition strategyDefinition; //虚拟化策略定义
        internal DataTemplate itemTemplateCache;
        internal DataTemplateSelector itemTemplateSelectorCache;
        internal string displayMemberPathCache;
        private PropertyInfo displayMemberPropInfo;
        internal DataTemplate headerTemplateCache;
        internal DataTemplate unionHeaderTemplateCache;

        #region Scroll
        internal ScrollBarVisibility verticalScrollBarVisibilityCache = ScrollBarVisibility.Auto;
        internal ScrollBarVisibility horizontalScrollBarVisibilityCache;
        protected ScrollState currentScrollState;
        #endregion

        private VisualStateGroup scrollStatesGroup;
        private VisualStateGroup verticalCompressionGroup;
        private GestureListener gestureListenter;
        private bool topBusyIndicatorShowed;
        #endregion

        #region Event
        public event EventHandler ScrolledToBottom;
        public event EventHandler StretchedFromTop;
        public event EventHandler<ItemTapedEventArgs> ItemTap;
        public event EventHandler<ScrollOffsetChangedEventArgs> ScrollOffsetChanged;
        #endregion

        #region Constructor

        public PhotoListBox()
        {
            base.DefaultStyleKey = typeof(PhotoListBox);
            this.realizedItems = new List<PhotoListBoxItem>();
            this.recycleItems = new List<PhotoListBoxItem>();
            this.listSource = this.InitializeListSource();
            this.SetupListSource();
            base.SizeChanged += PhotoListBox_SizeChanged;
        }      

        ~PhotoListBox()
        {
            Debug.WriteLine("PhotoListBox-销毁");
        }

        #endregion

        #region ApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            //base.UpdateVisualState(true);
            manipulationContainer = (ScrollViewer)base.GetTemplateChild("PART_ManipulationContainer");
            scrollableContent = (Canvas)base.GetTemplateChild("PART_ScrollableContent");
            itemsPanel = (Canvas)base.GetTemplateChild("PART_ItemsPanel");
            mainContainer = (StackPanel)base.GetTemplateChild("PART_MainContainer");
            unionHeaderElement = (ContentPresenter)base.GetTemplateChild("PART_UnionHeaderPresenter");
            if (hasUnionHeaderCache)
            {
                unionHeaderElement.Visibility = Visibility.Visible;
            }
            layoutRoot = (Grid)base.GetTemplateChild("LayoutRoot");
            //初始化状态变化事件
            this.InitializeManipulationContainer();
            //设置scrollbar绑定
            Binding binding = new Binding();
            binding.Source = this;
            binding.Path = new PropertyPath("(ScrollViewer.HorizontalScrollBarVisibility)", new object[0]);
            base.SetBinding(PhotoListBox.HorizontalScrollBarVisibilityProperty, binding);
            binding = new Binding();
            binding.Source = this;
            binding.Path = new PropertyPath("(ScrollViewer.VerticalScrollBarVisibility)", new object[0]);
            base.SetBinding(PhotoListBox.VerticalScrollBarVisibilityProperty, binding);

            base.SetBinding(VerticalOffsetProperty, new Binding("VerticalOffset") { Source = this.manipulationContainer });

            if (!DesignerProperties.IsInDesignTool)
            {
                PreLoadData();
            }
        }

        protected override void OnLoaded(object sender, RoutedEventArgs e)
        {
            base.OnLoaded(sender, e);
            if (DesignerProperties.IsInDesignTool)
            {
                PreLoadData();
            }
        }
        
        internal virtual void PreLoadData()
        {
            for (int i = 0; i < this.listSource.ListSourceItems.Count; i++)
            {
                IDataSourceItem dataSourceItem = this.listSource.ListSourceItems[i];
                this.strategy.RefreshViewportOnItemAdded(dataSourceItem);
            }
        }
        #endregion

        #region DependencyProperties

        #region ItemsSource
        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PhotoListBox), new PropertyMetadata(null, OnItemsSourceChanged));

        private static void OnItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox photoListBox = (PhotoListBox)sender;
            photoListBox.OnItemsSourceChanged(e);
        }

        internal virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            IEnumerable enumerable = e.NewValue as IEnumerable;
            listSource.SourceCollection = enumerable;
            if (enumerable == null && this.IsOperational())
            {
                ClearResource();
            }
        }

        #endregion

        #region DataTemplate
        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }

        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(PhotoListBox), new PropertyMetadata(null, OnItemTemplateChanged));

        private static void OnItemTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox ctrl = sender as PhotoListBox;
            ctrl.itemTemplateCache = e.NewValue as DataTemplate;
            ctrl.ResetOnTemplateChange();
        }

        internal void ResetOnTemplateChange()
        {
            if (this.realizedItems.Count == 0)
            {
                return;
            }
            //DataSourceItem dataSourceItem = this.GetTopVisibleItem();
        }
        #endregion

        #region ItemTemplateSelector
        public DataTemplateSelector ItemTemplateSelector
        {
            get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); }
            set { SetValue(ItemTemplateSelectorProperty, value); }
        }

        public static readonly DependencyProperty ItemTemplateSelectorProperty =
            DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(PhotoListBox), new PropertyMetadata(null, OnItemTemplateSelectorChanged));

        private static void OnItemTemplateSelectorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox ctrl = (PhotoListBox)sender;
            ctrl.itemTemplateSelectorCache = e.NewValue as DataTemplateSelector;
            ctrl.ResetOnTemplateChange();
        }
        #endregion

        #region DisplayMemberPath
        public string DisplayMemberPath
        {
            get { return (string)GetValue(DisplayMemberPathProperty); }
            set { SetValue(DisplayMemberPathProperty, value); }
        }

        public static readonly DependencyProperty DisplayMemberPathProperty =
            DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(PhotoListBox), new PropertyMetadata(null, OnDisplayMemberPathChanged));

        private static void OnDisplayMemberPathChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox ctrl = (PhotoListBox)sender;
            ctrl.displayMemberPathCache = (string)e.NewValue;
            ctrl.ValidateDisplayMemeberPath();
            ctrl.OnDisplayMemerPathChanged();
        }

        private void ValidateDisplayMemeberPath()
        {

        }

        protected virtual void OnDisplayMemerPathChanged()
        {

        }
        #endregion

        #region StrategyDefinition
        public VirtualizationStrategyDefinition StrategyDefinition
        {
            get { return (VirtualizationStrategyDefinition)GetValue(StrategyDefinitionProperty); }
            set { SetValue(StrategyDefinitionProperty, value); }
        }

        public static readonly DependencyProperty StrategyDefinitionProperty =
            DependencyProperty.Register("StrategyDefinition", typeof(VirtualizationStrategyDefinition), typeof(PhotoListBox), new PropertyMetadata(null, OnStrategyDefinitionChanged));

        private static void OnStrategyDefinitionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox ctrl = (PhotoListBox)sender;
            ctrl.OnStrategyDefinitionChanged(e);
        }

        internal virtual void OnStrategyDefinitionChanged(DependencyPropertyChangedEventArgs e)
        {
            VirtualizationStrategyDefinition strategyDefinition = (VirtualizationStrategyDefinition)e.NewValue;
            if (strategyDefinition == null)
            {
                throw new ArgumentNullException("strategyDefinition is null!");
            }
            this.ClearResource();
            if (this.strategyDefinition != null)
            {
                this.UpdateStrategyDefinitionChangeHandling(false);
                this.strategy.ResetOwner();
            }
            this.strategyDefinition = strategyDefinition;
            this.strategy = this.strategyDefinition.CreateStrategy();
            this.strategy.InitializeOwner(this);
            this.UpdateStrategyDefinitionChangeHandling(true);
        }

        private void UpdateStrategyDefinitionChangeHandling(bool subscribe)
        {
            this.strategyDefinition.PropertyChanged -= OnStrategyDefinitionPropertyChanged;
            if (subscribe)
            {
                this.strategyDefinition.PropertyChanged += OnStrategyDefinitionPropertyChanged;
            }

        }

        void OnStrategyDefinitionPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (base.IsLoaded)
            {
                strategyDefinition.SynchStrategyProperties(this.strategy);
            }
        }

        #endregion

        #region SelectedItemProperty
        public object SelectedItem
        {
            get { return (object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(object), typeof(PhotoListBox), new PropertyMetadata(null));

        #endregion

        #region EmptyTemplate
        
        #region EmptyContent
        public object EmptyContent
        {
            get { return (object)GetValue(EmptyContentProperty); }
            set { SetValue(EmptyContentProperty, value); }
        }

        public static readonly DependencyProperty EmptyContentProperty =
            DependencyProperty.Register("EmptyContent", typeof(object), typeof(PhotoListBox), new PropertyMetadata(OnEmptyContentChanged));

        private static void OnEmptyContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        #region EmptyContentTemplate

        public DataTemplate EmptyContentTemplate
        {
            get { return (DataTemplate)GetValue(EmptyContentTemplateProperty); }
            set { SetValue(EmptyContentTemplateProperty, value); }
        }

        public static readonly DependencyProperty EmptyContentTemplateProperty =
            DependencyProperty.Register("EmptyContentTemplate", typeof(DataTemplate), typeof(PhotoListBox), new PropertyMetadata(OnEmptyContentTemplateChanged));

        private static void OnEmptyContentTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }

        #endregion

        #region EmptyContentDisplayModeProperty

        #endregion


        #endregion

        #region VerticalOffsetProperty
        public static readonly DependencyProperty VerticalOffsetProperty =
            DependencyProperty.Register("VerticalOffset", typeof(double), typeof(PhotoListBox), new PropertyMetadata(0.0,OnVerticalOffsetChanged));

        private static void OnVerticalOffsetChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnVerticalOffsetChanged(e);
        }

        private void OnVerticalOffsetChanged(DependencyPropertyChangedEventArgs e)
        {
            //Debug.WriteLine("verticaloffset--->" + e.NewValue);
            OnVeticalScrollOffsetChanged(e);
        }
        #endregion

        #region ScrollbarVisibility

        #region VerticalScrollbarVisibility

        private static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
            DependencyProperty.Register("VerticalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(PhotoListBox), new PropertyMetadata(OnVerticalScrollBarVisibilityChanged));

        private static void OnVerticalScrollBarVisibilityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnVerticalScrollBarVisibilityChanged(e);
        }

        protected virtual void OnVerticalScrollBarVisibilityChanged(DependencyPropertyChangedEventArgs e)
        {
            this.verticalScrollBarVisibilityCache = (ScrollBarVisibility)e.NewValue;
            if (this.strategy != null)
            {
                strategy.UpdateScrollBarVisibility();
            }
        }

        #endregion

        #region HorizontalScrollbarVisibility

        private static readonly DependencyProperty HorizontalScrollBarVisibilityProperty =
            DependencyProperty.Register("HorizontalScrollBarVisibility", typeof(ScrollBarVisibility), typeof(PhotoListBox), new PropertyMetadata(OnHorizontalScollBarVisibilityChanged));

        private static void OnHorizontalScollBarVisibilityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnHorizontalScollBarVisibilityChanged(e);
        }

        protected virtual void OnHorizontalScollBarVisibilityChanged(DependencyPropertyChangedEventArgs e)
        {
            this.horizontalScrollBarVisibilityCache = (ScrollBarVisibility)e.NewValue;
            if (this.strategy != null)
            {
                strategy.UpdateScrollBarVisibility();
            }
        }
        #endregion


        #endregion

        #region HeaderBusyIndicator

        #region HeaderTemplate
        public DataTemplate HeaderContentTemplate
        {
            get { return (DataTemplate)GetValue(HeaderContentTemplateProperty); }
            set { SetValue(HeaderContentTemplateProperty, value); }
        }

        public static readonly DependencyProperty HeaderContentTemplateProperty =
            DependencyProperty.Register("HeaderContentTemplate", typeof(DataTemplate), typeof(PhotoListBox), new PropertyMetadata(OnHeaderContentTemplateChanged));

        private static void OnHeaderContentTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnHeaderContentTemplateChanged(e);
        }

        protected virtual void OnHeaderContentTemplateChanged(DependencyPropertyChangedEventArgs e)
        {
            headerTemplateCache = e.NewValue as DataTemplate;
        }
        #endregion

        #region HeaderContent
        public object HeaderContent
        {
            get { return (object)GetValue(HeaderContentProperty); }
            set { SetValue(HeaderContentProperty, value); }
        }

        public static readonly DependencyProperty HeaderContentProperty =
            DependencyProperty.Register("HeaderContent", typeof(object), typeof(PhotoListBox), new PropertyMetadata(OnHeaderContentChanged));

        private static void OnHeaderContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        #endregion

        #region ItemLoadingIndicator

        #region LoaingContent
        public object LoadingContent
        {
            get { return (object)GetValue(LoadingContentProperty); }
            set { SetValue(LoadingContentProperty, value); }
        }

        public static readonly DependencyProperty LoadingContentProperty =
            DependencyProperty.Register("LoadingContent", typeof(object), typeof(PhotoListBox), new PropertyMetadata(OnLoadingContentChanged));

        private static void OnLoadingContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        #region LoaingContentTemplate
        public DataTemplate LoadingContentTemplate
        {
            get { return (DataTemplate)GetValue(LoadingContentTemplateProperty); }
            set { SetValue(LoadingContentTemplateProperty, value); }
        }

        public static readonly DependencyProperty LoadingContentTemplateProperty =
            DependencyProperty.Register("LoadingContentTemplate", typeof(DataTemplate), typeof(PhotoListBox), new PropertyMetadata(OnLoadingContentTemplateChanged));

        private static void OnLoadingContentTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        #endregion

        #region LoadingData
        public bool Loading
        {
            get { return (bool)GetValue(LoadingProperty); }
            set { SetValue(LoadingProperty, value); }
        }

        public static readonly DependencyProperty LoadingProperty =
            DependencyProperty.Register("Loading", typeof(bool), typeof(PhotoListBox), new PropertyMetadata(false,OnLoadingChanged));

        private static void OnLoadingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnLoadingChanged(e);
        }

        protected virtual void OnLoadingChanged(DependencyPropertyChangedEventArgs e)
        {
            bool isLoading = (bool)e.NewValue;
            if (isLoading)
            {
                //Debug.WriteLine("显示加载中--->");
                ChangeVisualState("PullToDown");          
            }
            else
            {
                //Debug.WriteLine("不显示加载中--->");
                ChangeVisualState("Normal");
            }
        }
        #endregion

        #region UnionHeader

        #region UnionHeaderContent

        public object UnionHeaderContent
        {
            get { return (object)GetValue(UnionHeaderContentProperty); }
            set { SetValue(UnionHeaderContentProperty, value); }
        }

        public static readonly DependencyProperty UnionHeaderContentProperty =
            DependencyProperty.Register("UnionHeaderContent", typeof(object), typeof(PhotoListBox), new PropertyMetadata(OnUnionHeaderChanged));

        private static void OnUnionHeaderChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        #region UnionHeaderContentTemplate

        public DataTemplate UnionHeaderContentTemplate
        {
            get { return (DataTemplate)GetValue(UnionHeaderContentTemplateProperty); }
            set { SetValue(UnionHeaderContentTemplateProperty, value); }
        }

        public static readonly DependencyProperty UnionHeaderContentTemplateProperty =
            DependencyProperty.Register("UnionHeaderContentTemplate", typeof(DataTemplate), typeof(PhotoListBox), new PropertyMetadata(OnUnionHeaderContentTemplateChanged));

        private static void OnUnionHeaderContentTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as PhotoListBox).OnUnionHeaderContentTemplateChanged(e);
        }

        private void OnUnionHeaderContentTemplateChanged(DependencyPropertyChangedEventArgs e)
        {
            unionHeaderTemplateCache = (DataTemplate)e.NewValue;
        }

        #endregion


        #endregion

        internal bool hasUnionHeaderCache = false;

        public bool HasUnionHeader
        {
            get { return (bool)GetValue(HasUnionHeaderProperty); }
            set { SetValue(HasUnionHeaderProperty, value); }
        }

        public static readonly DependencyProperty HasUnionHeaderProperty =
            DependencyProperty.Register("HasUnionHeader", typeof(bool), typeof(PhotoListBox), new PropertyMetadata(false,OnHasUnionHeaderChanged));

        private static void OnHasUnionHeaderChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PhotoListBox ctrl = (PhotoListBox)sender;
            ctrl.OnHasUnionHeaderChanged(e);
        }

        private void OnHasUnionHeaderChanged(DependencyPropertyChangedEventArgs e)
        {
            hasUnionHeaderCache = (bool)e.NewValue;
        }

        #endregion

        #region Init

        #region InitListSource
        internal virtual NListSource InitializeListSource()
        {
            return new NListSource();
        }

        internal virtual void SetupListSource()
        {
            if (this.listSource != null)
            {
                this.listSource.CollectionChanged += OnlistSourceCollectionChanged;
            }
        }
        #endregion

        #region InitManipulationContainerScrollEvent
        private void InitializeManipulationContainer()
        {
            this.manipulationContainer.ApplyTemplate();
            IList visualStateGroups = VisualStateManager.GetVisualStateGroups(VisualTreeHelper.GetChild(this.manipulationContainer, 0) as FrameworkElement);
            scrollStatesGroup = visualStateGroups[0] as VisualStateGroup;
            scrollStatesGroup.CurrentStateChanging += OnScrollingStatesChanging;
            verticalCompressionGroup = visualStateGroups[1] as VisualStateGroup;
            verticalCompressionGroup.CurrentStateChanging += OnVerticalCompressionStatesChanging;
            //捕获上拉时的手势操作
            gestureListenter = GestureService.GetGestureListener(this.manipulationContainer);
            gestureListenter.DragDelta += new EventHandler<DragDeltaGestureEventArgs>(gestureListenter_DragDelta);
            gestureListenter.DragCompleted += new EventHandler<DragCompletedGestureEventArgs>(gestureListenter_DragCompleted);
        }

        #endregion

        #endregion

        #region Clear

        internal void OnCollectionReset()
        {
            for (int i = this.realizedItems.Count - 1; i >= 0; i--)
            {
                PhotoListBoxItem container = this.realizedItems[i];
                this.RecoveryContainer(container);
            }
            this.realizedItems.Clear();
        }

        internal void CleanupAfterCollectionReset()
        {
            if (this.IsPropertyTemplated)
            {
                this.manipulationContainer.ScrollToHorizontalOffset(0.0);
                this.manipulationContainer.ScrollToVerticalOffset(0.0);
            }
        }

        internal void ClearResource()
        {
            if (this.IsTemplateApplied)
            {
                //1.清空创建的布局
                this.OnCollectionReset();
                this.CleanupAfterCollectionReset();
            }
            
            for (int i = 0; i < this.recycleItems.Count; i++)
            {
                this.recycleItems[i] = null;
            }
            this.recycleItems.Clear();
            //this.recycleItems = null;
            //2.清空事件注册以及注册事件对象
            //if (scrollStatesGroup != null)
            //{
            //    scrollStatesGroup.CurrentStateChanging -= OnScrollingStatesChanging;
            //    scrollStatesGroup = null;
            //}
            //if (verticalCompressionGroup != null)
            //{
            //    verticalCompressionGroup.CurrentStateChanging -= OnVerticalCompressionStatesChanging;
            //    verticalCompressionGroup = null;
            //}
            //if (gestureListenter != null)
            //{
            //    gestureListenter.DragDelta -= new EventHandler<DragDeltaGestureEventArgs>(gestureListenter_DragDelta);
            //    gestureListenter.DragCompleted -= new EventHandler<DragCompletedGestureEventArgs>(gestureListenter_DragCompleted);
            //    gestureListenter = null;
            //}
            ////3.清空NListSource
            //if (this.listSource != null)
            //{
            //    this.listSource.CollectionChanged -= OnlistSourceCollectionChanged;
            //    this.listSource = null;
            //}
            //4.清空Strategy
            //if (this.strategy != null)
            //{
            //    this.strategy.ResetOwner();
            //}
        }

        #endregion

        #region Method

        #region Items add、remove、replace、reset about operator
        /// <summary>
        /// ListSourceChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnlistSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.OnItemsChanged(e);
        }

        /// <summary>
        /// 数据信息添加方法
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.strategy != null)
            {
                this.UpdateViewportOnItemsChange(e);
            }
            //base.UpdateVisualState(true);
        }
        /// <summary>
        /// 当数据信息添加时更新UI
        /// </summary>
        /// <param name="e"></param>
        private void UpdateViewportOnItemsChange(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (IsTemplateApplied)
                    {
                        this.strategy.RefreshViewportOnItemAdded(e.NewItems[0] as IDataSourceItem);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    this.strategy.RefreshViewportOnItemRemoved(e.OldItems[0] as IDataSourceItem, e.OldStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    this.strategy.RefreshViewportOnItemReplaced(e.NewItems[0] as IDataSourceItem);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    if (this.IsOperational())
                    {
                        this.strategy.RefreshViewportOnItemReset();
                    }
                    break;
                default:
                    break;
            }
        }

        #endregion

        #region Gesture
        void gestureListenter_DragCompleted(object sender, DragCompletedGestureEventArgs e)
        {
            if (topBusyIndicatorShowed)
            {
                ChangeVisualState("Normal");
            }
        }

        void gestureListenter_DragDelta(object sender, DragDeltaGestureEventArgs e)
        {
            if (e.VerticalChange > 100 && this.manipulationContainer.VerticalOffset == 0)
            {
                ChangeVisualState("PullToTop");
                topBusyIndicatorShowed = true;
            }
        }
        #endregion

        #region Scroll
        void OnVerticalCompressionStatesChanging(object sender, VisualStateChangedEventArgs e)
        {
            int itemCount = this.GetItemCount();
            if (e.NewState.Name == "CompressionTop")
            {
                //Debug.WriteLine("到顶部了--->");
                this.SetScrollState(ScrollState.TopStretch);
                return;
            }
            if (e.NewState.Name == "CompressionBottom")
            {
                //Debug.WriteLine("到底部了--->");
                this.SetScrollState(ScrollState.BottomStretch);
                return;
            }
            if (e.NewState.Name == "NoVerticalCompression")
            {
                //Debug.WriteLine("反弹---->");
                this.SetScrollState(ScrollState.Bouncing);
            }
        }

        void OnScrollingStatesChanging(object sender, VisualStateChangedEventArgs e)
        {
            if (e.NewState.Name == "Scrolling")
            {
                //Debug.WriteLine("滚动---->");
                this.SetScrollState(ScrollState.Scrolling);
            }
            else if (e.NewState.Name == "NotScrolling")
            {
                //Debug.WriteLine("停止滚动--->");
                this.SetScrollState(ScrollState.NotScrolling);
            }
        }
        /// <summary>
        /// 正在滑动的时候执行的方法
        /// </summary>
        protected virtual void OnVeticalScrollOffsetChanged(DependencyPropertyChangedEventArgs e)
        {
            double oldVerticalOffset = (double)e.OldValue;
            double newVerticalOffset = (double)e.NewValue;
            //Debug.WriteLine("oldVerticalOffset:" + oldVerticalOffset + "newVerticalOffset:" + newVerticalOffset);
            //处理预加载的情况
            var v1 = this.manipulationContainer.ExtentHeight - this.manipulationContainer.VerticalOffset;
            var v2 = this.manipulationContainer.ViewportHeight * 1.5;
            //在指定的范围内保证正方向加载数据
            if (v1 <= v2 && newVerticalOffset > oldVerticalOffset)
            {
                //Debug.WriteLine("触发请求---->");
                OnScrollToBottom();
            }
            this.BalanceVisualSpace(newVerticalOffset);
            //供revoke使用
            if (this.ScrollOffsetChanged != null)
            {
                double offsetChage = Math.Abs(newVerticalOffset - oldVerticalOffset);
                if (offsetChage > 100)
                {
                    this.ScrollOffsetChanged.Invoke(this, new ScrollOffsetChangedEventArgs(offsetChage));
                }
            }
        }

        protected virtual void SetScrollState(ScrollState newState)
        {
            ScrollState oldState = this.currentScrollState;
            this.currentScrollState = newState;
            if (oldState != newState)
            {
                if (oldState == ScrollState.BottomStretch && newState == ScrollState.Bouncing)
                {
                    //Debug.WriteLine("加载老数据-->");
                    return;
                }
                if (oldState == ScrollState.Scrolling && newState == ScrollState.TopStretch)
                {
                    return;
                }
                if (oldState == ScrollState.TopStretch && newState == ScrollState.Bouncing)
                {
                    if (topBusyIndicatorShowed)
                    {
                        topBusyIndicatorShowed = false;
                        OnStretchFromTop();
                    }
                    return;
                }
            }
        }
        #endregion

        #region Virtualize
        /// <summary>
        /// 虚拟化
        /// </summary>
        internal void BalanceVisualSpace(double offset)
        {
            if (!this.IsOperational() || this.GetItemCount() <= 0)
            {
                return;
            }
            if (this.UnionHeaderContent != null || this.UnionHeaderContentTemplate != null)
            {
                this.strategy.ReCaculateContainer(offset - this.unionHeaderElement.ActualHeight);
                return;
            }
            this.strategy.ReCaculateContainer(offset);
        }

        internal void ChangePanelHeight(double height)
        {
            PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
            if (frame != null)
            {
                PhoneApplicationPage currentPage = frame.Content as PhoneApplicationPage;
                if (currentPage != null && currentPage.ApplicationBar != null && currentPage.ApplicationBar.IsVisible && currentPage.ApplicationBar.Opacity > 0.5)
                {
                    this.scrollableContent.Height = height + 72;
                }
                else
                {
                    this.scrollableContent.Height = height;
                }
            }
        }
        #endregion
        
        #region StateChange

        #region ItemTap
        internal void OnItemTap(PhotoListBoxItem tapedItem)
        {
            this.SelectedItem = tapedItem.associatedDataItem.Value;
            OnItemTapOverride(tapedItem);
        }

        protected virtual void OnItemTapOverride(PhotoListBoxItem tapedItem)
        {
            OnItemTaped(tapedItem);
        }

        #endregion

        internal void ChangeVisualState(string stateName)
        {
            VisualStateManager.GoToState(this, stateName, false);
        }
       
        #endregion       

        #region EventDeal

        /// <summary>
        /// 处理事件
        /// </summary>
        /// <param name="tapedItem"></param>
        protected virtual void OnItemTaped(PhotoListBoxItem tapedItem)
        {
            if (this.ItemTap != null)
            {
                this.ItemTap.Invoke(this, new ItemTapedEventArgs(tapedItem.associatedDataItem.Value));
            }
        }

        protected virtual void OnScrollToBottom()
        {
            if (this.ScrolledToBottom != null)
            {
                this.ScrolledToBottom.Invoke(this, EventArgs.Empty);
            }
        }

        protected virtual void OnStretchFromTop()
        {
            if (this.StretchedFromTop != null)
            {
                this.StretchedFromTop.Invoke(this, EventArgs.Empty);
            }
        }
        #endregion

        #region TopBottomItem
        internal IDataSourceItem GetTopVisibleItem(double verticalOffset)
        {
            double scrollOffset = this.manipulationContainer.VerticalOffset;
            IDataSourceItem currentItem = this.listSource.ListSourceItems[0];
            while (currentItem != null)
            {
                double offset = currentItem.Y - scrollOffset;
                if (offset >= -NEnviroment.ScrreenHeight)
                {
                    break;
                }
                currentItem = currentItem.Next;
            }
            return currentItem;
        }

        internal IDataSourceItem GetBottomVisibleItem(double verticalOffset)
        {
            double scrollOffset = this.manipulationContainer.VerticalOffset;
            IDataSourceItem currentItem = this.listSource.ListSourceItems[this.GetItemCount() - 1];
            while (currentItem != null)
            {
                double offset = currentItem.Y - scrollOffset;
                if (offset < NEnviroment.ScrreenHeight * 2)
                {
                    break;
                }
                currentItem = currentItem.Previous;
            }
            return currentItem;
        }

        #endregion

        #region CyclicContainer
        internal void RealizedNewContainer(IDataSourceItem addedItem)
        {
            addedItem.IsShowed = true;
            PhotoListBoxItem container = this.GenerateContainerForItem();
            this.PrepareContainerForItemOverride(container, addedItem);
            this.SetContainerSize(addedItem, container);
            this.itemsPanel.Children.Add(container);
            InsertIntoViewPort(container);
            RealizedNewContainerOverride(container);
        }

        protected virtual void RealizedNewContainerOverride(PhotoListBoxItem container) 
        {
            
        }

        internal PhotoListBoxItem GetRealizedContainerByItem(IDataSourceItem item)
        {
            return this.realizedItems.Where(x => x.associatedDataItem == item).FirstOrDefault();
        }

        internal IDataSourceItem GetDataSourceItemByIndex(int index)
        {
            if (index >= GetItemCount())
            {
                index = GetItemCount() - 1;
            }
            if (GetItemCount() > 0)
            {
                return this.listSource.ListSourceItems.ElementAt(index);
            }
            return null;
        }

        internal void RealizedOldContainer(PhotoListBoxItem oldContainer)
        {
            SetContainerSize(oldContainer.associatedDataItem, oldContainer);
        }
        /// <summary>
        /// 回收不用的Container
        /// </summary>
        /// <param name="container"></param>
        internal void RecoveryContainer(PhotoListBoxItem container)
        {
            RecoveryContainerOverride(container);
            this.itemsPanel.Children.Remove(container);
            container.Width = 0;
            container.Height = 0;
            container.SetVerticalOffset(0);
            container.SetHorizontalOffset(0);
            container.associatedDataItem.IsShowed = false;
            container.Detach();
            this.ClearContainerForItemOverride(container, container.associatedDataItem);
            this.realizedItems.Remove(container);
        }
        /// <summary>
        /// 在放回容器池时之前的操作
        /// </summary>
        /// <param name="container"></param>
        protected virtual void RecoveryContainerOverride(PhotoListBoxItem container) 
        {
        
        }

        private void SetContainerSize(IDataSourceItem addedItem, PhotoListBoxItem container)
        {
            container.Width = addedItem.Width;
            container.Height = addedItem.Height;
            Debug.WriteLine("x:" + addedItem.X + "y:" + addedItem.Y);
            container.SetHorizontalOffset(addedItem.X);
            container.SetVerticalOffset(addedItem.Y);
        }

        private void InsertIntoContainerPool(PhotoListBoxItem container)
        {
            this.recycleItems.Add(container);
        }

        internal virtual void InsertIntoViewPort(PhotoListBoxItem container)
        {
            this.realizedItems.Add(container);
        }
        #endregion

        #region Container

        /// <summary>
        /// 给sourcitem 生成container
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal PhotoListBoxItem GenerateContainerForItem()
        {
            PhotoListBoxItem container = this.GetRecycleContainerForItem();
            container.CacheMode = new BitmapCache();
            return container;
        }

        internal void PrepareContainerForItemInternal(DependencyObject element, IDataSourceItem item)
        {
            this.PrepareContainerForItemOverride(element, item);
        }

        protected virtual void PrepareContainerForItemOverride(DependencyObject element, IDataSourceItem item)
        {
            PhotoListBoxItem container = (PhotoListBoxItem)element;
            //绑定数据源
            container.BindToDataItem(item);
            //设置样式
            this.PrepareStyle(container, item);
            //设置ItemContainer的Content 和ContentTemplate
            if (item.Value != NListSource.UnsetObject)
            {
                this.PrepareDataItem(container, item);
            }
        }

        protected virtual void ClearContainerForItemOverride(DependencyObject element, IDataSourceItem item)
        {
            PhotoListBoxItem container = (PhotoListBoxItem)element;
            container.RealeaseFromDataItem();
        }

        /// <summary>
        /// 设置Content和ContentTemplate
        /// </summary>
        /// <param name="container"></param>
        /// <param name="item"></param>
        internal void PrepareDataItem(PhotoListBoxItem container, IDataSourceItem item)
        {
            //TemplateSelector的情况
            if (this.itemTemplateSelectorCache != null)
            {
                DataTemplate dataTemplate = this.itemTemplateSelectorCache.SelectTemplate(item.Value, container);
                if (dataTemplate != null)
                {
                    container.Content = item.Value;
                    container.ContentTemplate = dataTemplate;
                    return;
                }
            }
            //用ItemTemplate的情况
            if (this.itemTemplateCache != null)
            {
                container.Content = item.Value;
                container.ContentTemplate = this.itemTemplateCache;
                return;
            }
            //用DisplayMemberPath的情况
            if (container.ContentTemplate != null)
            {
                container.ContentTemplate = null;
            }
            if (!string.IsNullOrEmpty(this.displayMemberPathCache))
            {
                if (item.DisplayValue == null)
                {
                    object displayValue = this.ReflectPropertyValueAndStoreInfoIfNeeded(ref this.displayMemberPropInfo, item.Value, displayMemberPathCache);
                    item.DisplayValue = displayValue;
                }
                container.Content = item.DisplayValue;
                return;
            }
            if (item.Value != null)
            {
                container.Content = item.Value;
            }
        }
        /// <summary>
        /// 根据item 和 DisplayMemberPath 获取content 的值
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="p"></param>
        /// <param name="displayMemberPathCache"></param>
        /// <returns></returns>
        internal virtual object ReflectPropertyValueAndStoreInfoIfNeeded(ref PropertyInfo propertyInfo, object source, string propertyPath)
        {
            Type type = source.GetType();
            if (propertyInfo != null && propertyInfo.Name == propertyPath && propertyInfo.DeclaringType == type)
            {
                return propertyInfo.GetValue(source, new object[0]);
            }
            if (!string.IsNullOrEmpty(propertyPath))
            {
                propertyInfo = type.GetProperty(propertyPath);
                if (propertyInfo != null)
                {
                    return propertyInfo.GetValue(source, new object[0]);
                }
            }
            return null;
        }

        private void PrepareStyle(PhotoListBoxItem container, IDataSourceItem item)
        {

        }

        /// <summary>
        /// 获得Container容器
        /// 如果容器池(realizedItems)中空闲的则直接取出空闲的一个
        /// 如果不够了再创造一个
        /// </summary>
        /// <returns></returns>
        private PhotoListBoxItem GetRecycleContainerForItem()
        {
            IEnumerable<PhotoListBoxItem> freeRecycleItems = this.recycleItems.Where(x => !x.IsBusy);
            //Debug.WriteLine("容器池中的数量:" + recycleItems.Count);
            if (freeRecycleItems.Count() == 0)
            {
                PhotoListBoxItem newContainer = (PhotoListBoxItem)GetContainerForItemOverride();
                newContainer.Attach(this);
                InsertIntoContainerPool(newContainer);
                return newContainer;
            }
            freeRecycleItems.FirstOrDefault().Attach(this);
            return freeRecycleItems.FirstOrDefault();
        }

        protected virtual DependencyObject GetContainerForItemOverride() 
        {
            return new PhotoListBoxItem();
        }

        #endregion

        #region OtherMethod

        /// <summary>
        /// 判断当前容器是否具备了可操作的条件
        /// </summary>
        /// <returns></returns>
        internal virtual bool IsOperational()
        {
            //&& this.GetItemCount() > 0
            return base.IsLoaded && this.strategy != null && this.itemsPanel != null ;
        }



        /// <summary>
        /// 获取数据源的数量
        /// </summary>
        /// <returns></returns>
        internal virtual int GetItemCount()
        {
            return this.listSource.Count;
        }

        protected override string ComposeVisualStateName()
        {
            if (this.listSource.SourceCollection != null && this.listSource.Count == 0) { return "NoData"; }
            return "Normal";
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            return base.MeasureOverride(availableSize);
        }

        void PhotoListBox_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            //RectangleGeometry rectangleGeometry = new RectangleGeometry();
            //rectangleGeometry.Rect = new Rect(0.0, 0.0, e.NewSize.Width,e.NewSize.Height);
            //base.Clip = rectangleGeometry;
            //this.strategy.OnViewportSizeChanged(e.NewSize, e.PreviousSize);
        }
        #endregion

        #endregion

        #region Implements
        public FrameworkElement[] ViewportItems
        {
            get { return this.realizedItems.ToArray(); }
        }
        #endregion
    }
}
